﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using AdvplDoc.Model;

namespace AdvplDoc.View {

    class WikiMarkupPrinter : AbstractPrinter {

        static string HEADER =
            "{composition-setup}\n" +
            "import.css=/download/attachments/6062824/tecnologia.css\n" +
            "{composition-setup}\n" +
            "\n" +
            "{portuguese}\n";

        static string FOOTER =
            "\n{portuguese}";

        public WikiMarkupPrinter(string output_path) : base(output_path) {
            this.fileExtension = "txt";
        }

        override internal void process(Parser parser, System.Action<int> start, System.Action<int> update) {
            int totalClasses = parser.classes.Count;
            int totalFunctions = parser.functions.Count;

            start(totalClasses /*+ totalFunctions*/);

            List<AdvplClass> classes = parser.getClassList();

            for (int i = 0; i < totalClasses; i++) {
                AdvplClass klass = classes[i];

                this.processClass(klass);
                this.processConstructors(klass);
                this.processProperties(klass);
                this.processMethods(klass);

                update(i);
            }

            /*
            for (int i = 0; i < totalFunctions; i++) {
                AdvplFunction function = parser.functions[i];

                this.process_function(function);

                update(i);
            }
            */
        }

        private void processConstructors(AdvplClass klass) {
            string directory = "classes\\" + klass.name + "\\constructors";

            foreach (AdvplMethod constructor in klass.constructors.Values) {
                string content = this.getConstructorTemplate(constructor);

                this.write(directory, constructor.name, content);
            }

        }

        private void processProperties(AdvplClass klass) {
            string directory = "classes\\" + klass.name + "\\properties";

            foreach (AdvplProperty prop in klass.getProperties(true)) {
                string content = this.getPropertiesTemplate(klass, prop);

                this.write(directory, prop.name, content);
            }
        }

        private void processMethods(AdvplClass klass) {
            string directory = "classes\\" + klass.name + "\\methods";

            foreach (AdvplMethod method in klass.getMethods(true)) {
                string content = this.getMethodTemplate(klass, method);

                this.write(directory, method.name, content);
            }

        }

        private string getMethodTemplate(AdvplClass klass, AdvplMethod method) {
            StringBuilder sb = new StringBuilder();

            sb.AppendLine(HEADER);
            sb.Append("{pagetitle:").Append(klass.name).Append(":").Append(method.name).Append("}");
            sb.AppendLine();

            if (method.description != "") {
                sb.AppendLine(method.description);
                sb.AppendLine();
            }

            sb.AppendLine("h2. Sintaxe");
            sb.AppendLine("{code}");

            if (method.returnInfo != null)
                sb.Append(method.returnInfo.name.ToString()).Append(" := ");

            sb.Append(method.name).Append("(");

            if (method.parameters.Count > 0)
                sb.Append("<").Append(String.Join(">, <", method.getParametersNames())).Append(">");          

            sb.AppendLine(")");
            sb.AppendLine("{code}");
            sb.AppendLine();
            
            sb.AppendLine("h2. Parâmetros");
            sb.AppendLine();

            if (method.returnInfo != null) {
                sb.AppendLine("h2. Retorno");

                sb.AppendLine(method.returnInfo.name);
                sb.AppendLine(method.returnInfo.type.ToString());
                sb.AppendLine();
            }

            if (method.observation.Count > 0) {
                sb.AppendLine("h2. Observações");
                
                foreach (string obs in method.observation) {
                    sb.AppendLine(obs);
                }

                sb.AppendLine();
            }

            sb.AppendLine("h2. Exemplos");
            sb.AppendLine();

            sb.AppendLine(FOOTER);

            return sb.ToString();
        }

        private string getPropertiesTemplate(AdvplClass klass, AdvplProperty prop) {
            StringBuilder sb = new StringBuilder();

            sb.AppendLine(HEADER);
            sb.Append("{pagetitle:").Append(klass.name).Append(":").Append(prop.name).Append("}");
            sb.AppendLine();

             if (prop.description != "") {
                sb.AppendLine(prop.description);
                sb.AppendLine();
            }

            sb.AppendLine("|| Tipo || Valor Padrão ||");
            sb.Append("| ").Append(prop.type.ToString()).Append(" ");
            sb.Append("| ").Append(prop.defaultValue).AppendLine(" |");

            if (prop.observation.Count > 0) {
                sb.AppendLine("h2. Observações");
                
                foreach (string obs in prop.observation) {
                    sb.AppendLine(obs);
                }

                sb.AppendLine();
            }

            /*
            h4. Exemplo

            {code}
            Local oMessage := tMailMessage():New()

            oMessage:nXPriority := 1
            {code}

            {portuguese}
                        */

            sb.AppendLine(FOOTER);

            return sb.ToString();
        }

        private string getConstructorTemplate(AdvplMethod constructor) {
            StringBuilder sb = new StringBuilder();

            return sb.ToString();
        }

        public void processClass(AdvplClass klass) {
            StringBuilder sb = this.getClassTemplate(klass);

            this.write("classes\\" + klass.name, klass.name, sb);
        }

        private StringBuilder getClassTemplate(AdvplClass klass) {
            StringBuilder sb = new StringBuilder();

            sb.AppendLine(HEADER);

            sb.Append("{pagetitle:Classe ").Append(klass.name).Append("}");
            sb.AppendLine();

            if (klass.description != "") {
                sb.AppendLine(klass.description);
                sb.AppendLine();
            }

            sb.AppendLine("h2. Hierarquia");

            string bullet = "*";
            foreach (AdvplClass c in klass.getHierarchy()) {
                sb.Append(bullet).Append(" ").AppendLine(c.name);
                bullet += "*";
            }

            sb.AppendLine();

            if (klass.constructors.Count > 0) {
                sb.Append("h2. Construtores").AppendLine();
                sb.Append("{excerpt-include:Classe ").Append(klass.name).Append(" - Construtores|nopanel=true}").AppendLine();
                sb.AppendLine();
            }

            if (klass.properties.Count > 0) {
                sb.Append("h2. Propriedades").AppendLine();
                sb.Append("{excerpt-include:Classe ").Append(klass.name).Append(" - Propriedades|nopanel=true}").AppendLine();
                sb.AppendLine();
            }

            if (klass.methods.Count > 0) {
                sb.Append("h2. Métodos").AppendLine();
                sb.Append("{excerpt-include:Classe ").Append(klass.name).Append(" - Métodos|nopanel=true}").AppendLine();
                sb.AppendLine();
            }

            if (klass.observation.Count > 0) {
                sb.AppendLine("h2. Observações");

                foreach (string obs in klass.observation) {
                    sb.AppendLine(obs);
                }

                sb.AppendLine();
            }

            if (klass.examples.Count > 0) {
                sb.AppendLine("h2. Exemplos");

                foreach (string ex in klass.examples) {
                    int index = klass.examples.IndexOf(ex);

                    sb.Append("{code:title=Exemplo ").Append(index + 1);
                    sb.AppendLine("|theme=Eclipse|linenumbers=true|language=cpp}");
                    sb.AppendLine(ex.Replace(Constants.PRE_BEGIN_TAG, "").Replace(Constants.PRE_END_TAG, ""));
                    sb.AppendLine("{code}");
                }

                sb.AppendLine();
            }


            if (klass.since != "") {
                sb.AppendLine("h2. Abrangência");
                sb.AppendLine(klass.since);
                sb.AppendLine();
            }

            if (klass.seeAlso.Count > 0) {
                sb.AppendLine("h2. Veja também");

                foreach (string see in klass.seeAlso) {
                    sb.AppendLine(see);
                }

                sb.AppendLine();
            }


            sb.AppendLine(FOOTER);

            return sb;
        }
    }
}
